/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Engine2D.level;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.util.Map;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import Engine2D.level.tile.TileManager;

/**
 *
 * @author gary.morris
 */
public class LevelGenerator {

    private static final Random random = new Random();
    private int w, h;
    private final double[][] grid;
    private int sampleSize;

    /**
     * 
     * @param w
     * @param h
     * @param sampleSize
     */
    public LevelGenerator(int w, int h, int sampleSize) {
        this.w = w;
        this.h = h;
        this.sampleSize = sampleSize;
        grid = new double[w][h];


        init();
    }

    private void init() {
        int xh = grid.length - 1;
        int yh = grid.length - 1;

        // set the corner points
        grid[0][0] = random.nextFloat() - 0.5f;
        grid[0][yh] = random.nextFloat() - 0.5f;
        grid[xh][0] = random.nextFloat() - 0.5f;
        grid[xh][yh] = random.nextFloat() - 0.5f;

        // generate the fractal
        generate(0, 0, xh, yh);
    }

    // generate the fractal
    private void generate(int xl, int yl, int xh, int yh) {
        int xm = (xl + xh) / 2;
        int ym = (yl + yh) / 2;
        if ((xl == xm) && (yl == ym)) {
            return;
        }

        grid[xm][yl] = 0.5f * (grid[xl][yl] + grid[xh][yl]);
        grid[xm][yh] = 0.5f * (grid[xl][yh] + grid[xh][yh]);
        grid[xl][ym] = 0.5f * (grid[xl][yl] + grid[xl][yh]);
        grid[xh][ym] = 0.5f * (grid[xh][yl] + grid[xh][yh]);

        double v = roughen(0.5f * (grid[xm][yl] + grid[xm][yh]), xl + yl, yh
                + xh);
        grid[xm][ym] = v;
        grid[xm][yl] = roughen(grid[xm][yl], xl, xh);
        grid[xm][yh] = roughen(grid[xm][yh], xl, xh);
        grid[xl][ym] = roughen(grid[xl][ym], yl, yh);
        grid[xh][ym] = roughen(grid[xh][ym], yl, yh);

        generate(xl, yl, xm, ym);
        generate(xm, yl, xh, ym);
        generate(xl, ym, xm, yh);
        generate(xm, ym, xh, yh);
    }

    // Add a suitable amount of random displacement to a point
    private double roughen(double v, int l, int h) {
        return v + sampleSize * (double) (random.nextGaussian() * (h - l));
    }

    /**
     * Dump out as a CSV
     */
    public void printAsCSV() {
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                System.out.print(grid[i][j]);
                System.out.print(",");
            }
            System.out.println();
        }
    }

    /**
     * 
     * @param w
     * @param h
     * @return
     */
    public static byte[][] createMap(int w, int h) {

        byte[] map = new byte[w * h];
        byte[] data = new byte[w * h];

        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {

                int i = x + y * w;



                int r = random.nextInt(30);
                if (r < 3) {
                    map[i] = TileManager.rock.id;
                } else if (r < 15) {
                    map[i] = TileManager.water.id;
                } else {
                    map[i] = TileManager.grass.id;
                }
map[i] = TileManager.rock.id;

map[1] = TileManager.grass.id;
            }

        }





        return new byte[][]{map, data};
    }

    /**
     * 
     * @param w
     * @param h
     * @return
     */
    public static byte[][] createNoiseMap(int w, int h) {

        LevelGenerator gen = new LevelGenerator(w, h, 5);


        byte[] map = new byte[w * h];
        byte[] data = new byte[w * h];

        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {

                int i = x + y * w;


                if (gen.grid[x][y] < x) {
                    map[i] = TileManager.water.id;
                } else if (gen.grid[x][y] > x * 10) {
                    map[i] = TileManager.rock.id;
                } else {
                    map[i] = TileManager.grass.id;
                }

            }

        }



        for (int i = 0; i < w * h / 2800; i++) {

            int xs = random.nextInt(w);
            int ys = random.nextInt(h);

            for (int k = 0; k < 10; k++) {
                int x = xs + random.nextInt(10);
                int y = ys + random.nextInt(10);

                for (int j = 0; j < 100; j++) {
                    int xo = x + random.nextInt(5) - random.nextInt(5);
                    int yo = y + random.nextInt(5) - random.nextInt(5);

                    
                    for (int yy = yo - 1; yy < yo + 1; yy++) {
                        for (int xx = xo - 1; xx < xo + 1; xx++) {
                            if (xx >= 0 && yy >= 0 && xx < w && yy < h) {
                                if (map[xx + yy * w] == TileManager.grass.id) {
                                    map[xx + yy * w] = TileManager.sand.id;
                                }
                            }
                        }
                    }
                }
            }
        }


        for (int i = 0; i < w * h / 100; i++) {
            int xx = random.nextInt(w);
            int yy = random.nextInt(h);
            if (xx >= 0 && yy >= 0 && xx < w && yy < h) {
                if (map[xx + yy * w] == TileManager.rock.id) {
                    map[xx + yy * w] = TileManager.ore.id;
                }
            }
        }


        return new byte[][]{map, data};

    }

    /**
     * 
     * @param w
     * @param h
     * @return
     */
    public static byte[][] validNoiseMap(int w, int h) {

        byte[][] result = createNoiseMap(w, h);
        int[] count = new int[256];
        
        do {
            
            result = createNoiseMap(w, h);

            //int[] count = new int[256];

            for (int i = 0; i < w * h; i++) {
                count[result[0][i] & 0xff]++;
            }
            System.out.println(count[TileManager.rock.id & 0xff] + " rock tles.");
            System.out.println(count[TileManager.water.id & 0xff] + " water tles.");
            System.out.println(count[TileManager.grass.id & 0xff] + " grass tles.");
            

            if (count[TileManager.rock.id & 0xff] < ((w * h) * 0.1)) {
                continue;
            }
            if (count[TileManager.grass.id & 0xff] < ((w * h) * 0.1)) {
                continue;
            }
            return result;

        } while (true);
    }

    /**
     * 
     * @param args
     */
    public static void main(String args[]) {
        int d = 0;
        while (true) {
            int w = 1000;
            int h = 1000;

            byte[] map = LevelGenerator.createNoiseMap(w, h)[0];
            // byte[] map = LevelGen.createAndValidateUndergroundMap(w, h, (d++ % 3) + 1)[0];
            // byte[] map = LevelGen.createAndValidateSkyMap(w, h)[0];

            BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
            int[] pixels = new int[w * h];
            for (int y = 0; y < h; y++) {
                for (int x = 0; x < w; x++) {
                    int i = x + y * w;

                    if (map[i] == TileManager.water.id) {
                        pixels[i] = 0x000080;
                    }
                    if (map[i] == TileManager.grass.id) {
                        pixels[i] = 0x208020;
                    }
                    if (map[i] == TileManager.rock.id) {
                        pixels[i] = 0xa0a0a0;
                    }

                }
            }
            img.setRGB(0, 0, w, h, pixels, 0, w);
            JOptionPane.showMessageDialog(null, null, "Another", JOptionPane.YES_NO_OPTION, new ImageIcon(img.getScaledInstance(w * 1, h * 1, Image.SCALE_AREA_AVERAGING)));
        }
    }
}
